package com.atguigu.tingshu.search.cron;

import com.atguigu.tingshu.search.service.impl.ItemServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;

/**
 * @Author：yyj
 * @Package：com.atguigu.tingshu.search.cron
 * @Project：tingshu_parent240829
 * @name：RebuildDistroBloomFilterTask
 * @Date：2025/2/14 19:45
 * @Filename：RebuildDistroBloomFilterTask
 */
@Component
@Slf4j
public class RebuildDistroBloomFilterTask {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ItemServiceImpl itemService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * cron表达式
     * * * * * * * （*）不用
     * <p>
     * *（秒） 0-59
     * *（分） 0-59
     * * (时) 0-23
     * * (日) 1-31
     * * (月) 1-12（JAN-DEC）
     * * (周)（SUN-SAT） 0-7（0 7代表周日）
     * 注意：日周不能同时出现一个具体值（会冲突）一个写具体指 另一个写?
     * 注意：,(多值) -（范围） ? *（任意值） /(区间 范围)
     * 如果数据库数据经常变化 那么同步时间就要短一些  如果不经常变换 同步时间就可以变长一些
     * 每7天凌晨2点钟进行同步
     */

//    @Scheduled(cron = "0 0/2 * * * ? ")  // 测试环境每隔2min执行一下
//    @Scheduled(cron = "0 0 2 0/7 * ? ")  // 真实环境
    public void rebuildDistroBloomFilter() {
        RBloomFilter<Object> newBloomFilter = redissonClient.getBloomFilter("albumIdBloomFilterNew");
        newBloomFilter.tryInit(1000000, 0.03);
        List<Long> albumIds = itemService.getAlbumdIds();
        if (!CollectionUtils.isEmpty(albumIds)) {
            for (Long albumId : albumIds) {
                newBloomFilter.add(albumId);
            }
            newBloomFilter.add(10000L); // 测试时候一定要给L (太坑)
            log.info("新的分布式布隆过滤器数据初始化完毕，且元素个数为：{}", newBloomFilter.count());
        }
        // 优化：删除老布隆和新建布隆以及放数据和替换做为一个原子操作
        String script = " redis.call(\"del\",KEYS[1])" + "  redis.call(\"del\",KEYS[2])" + "  redis.call(\"rename\",KEYS[3],KEYS[1])" + "  redis.call(\"rename\",KEYS[4],KEYS[2]) return 1";
        List<String> asList = Arrays.asList("albumIdBloomFilter", "{albumIdBloomFilter}:config", "albumIdBloomFilter:new", "{albumIdBloomFilter:new}:config");

        Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), asList);
        if (execute == 1) {
            log.info("新布隆已经上线");
        } else {
            log.info("老布隆在线，使用的依然是老布隆");
        }
    }
}